using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MT5Trade.Models
{
    /// <summary>
    /// 基于泊松过程的重试间隔计算器
    /// 实现科学的重试策略，基于泊松分布优化重试间隔和次数
    /// 核心数学模型：P(失败) = e^(-λt), P_success(n) = 1 - e^(-nλt)
    /// </summary>
    public class PoissonRetryCalculator
    {
        #region 常量定义

        // 默认泊松参数
        private const double DEFAULT_LAMBDA = 2.0;           // 默认泊松参数λ=2.0
        private const double MIN_LAMBDA = 0.1;               // 最小λ值
        private const double MAX_LAMBDA = 10.0;              // 最大λ值
        
        // 成本参数
        private const double DEFAULT_ATTEMPT_COST = 1.0;     // 单次重试成本
        private const double DEFAULT_TIME_COST = 0.01;       // 单位时间成本
        private const double DEFAULT_FAILURE_COST = 100.0;   // 失败成本
        
        // 策略阈值
        private const double TARGET_SUCCESS_RATE = 0.99;     // 目标成功率99%
        private const double VOLATILITY_HIGH_THRESHOLD = 0.8; // 高波动阈值
        private const double VOLATILITY_NORMAL_THRESHOLD = 0.5; // 正常波动阈值
        
        // 统计参数
        private const int HISTORY_WINDOW_SIZE = 100;         // 历史数据窗口大小
        private const double LEARNING_RATE = 0.1;            // 学习率

        #endregion

        #region 字段和属性

        private double _lambda;                               // 当前泊松参数
        private readonly double _attemptCost;
        private readonly double _timeCost;
        private readonly double _failureCost;
        
        // 历史数据统计
        private readonly Queue<RetryAttemptRecord> _attemptHistory;
        private readonly Dictionary<string, OperationStatistics> _operationStats;
        private readonly object _statisticsLock = new object();
        private readonly IRandomProvider _randomProvider;

        /// <summary>
        /// 当前泊松参数λ
        /// </summary>
        public double Lambda => _lambda;
        
        /// <summary>
        /// 历史记录数量
        /// </summary>
        public int HistoryCount => _attemptHistory.Count;

        #endregion

        #region 构造函数

        /// <summary>
        /// 创建泊松重试计算器实例
        /// </summary>
        /// <param name="initialLambda">初始λ参数</param>
        /// <param name="attemptCost">单次重试成本</param>
        /// <param name="timeCost">单位时间成本</param>
        /// <param name="failureCost">失败成本</param>
        /// <param name="randomProvider">随机数提供器（可选）</param>
        public PoissonRetryCalculator(
            double initialLambda = DEFAULT_LAMBDA,
            double attemptCost = DEFAULT_ATTEMPT_COST,
            double timeCost = DEFAULT_TIME_COST,
            double failureCost = DEFAULT_FAILURE_COST,
            IRandomProvider randomProvider = null)
        {
            _lambda = Math.Max(MIN_LAMBDA, Math.Min(MAX_LAMBDA, initialLambda));
            _attemptCost = attemptCost;
            _timeCost = timeCost;
            _failureCost = failureCost;
            
            _attemptHistory = new Queue<RetryAttemptRecord>();
            _operationStats = new Dictionary<string, OperationStatistics>();
            
            // 使用提供的随机数生成器或创建确定性生成器
            _randomProvider = randomProvider ?? 
                DeterministicRandomProvider.CreateForOptimization($"PoissonRetry_{DateTime.Today:yyyyMMdd}");
        }

        #endregion

        #region 核心计算方法

        /// <summary>
        /// 计算基于泊松过程的最优重试策略
        /// </summary>
        /// <param name="operationType">操作类型</param>
        /// <param name="currentVolatility">当前市场波动率</param>
        /// <param name="systemLoad">系统负载(0-1)</param>
        /// <returns>最优重试策略</returns>
        public PoissonRetryStrategy CalculateOptimalStrategy(string operationType, double currentVolatility = 0.5, double systemLoad = 0.5)
        {
            // 1. 动态调整λ参数
            double adjustedLambda = AdjustLambdaForConditions(operationType, currentVolatility, systemLoad);
            
            // 2. 计算最优重试次数
            int optimalRetries = CalculateOptimalRetryCount(adjustedLambda);
            
            // 3. 计算重试间隔序列
            var retryIntervals = CalculateRetryIntervals(adjustedLambda, optimalRetries);
            
            // 4. 计算成功概率
            double successProbability = CalculateSuccessProbability(adjustedLambda, optimalRetries);
            
            // 5. 计算期望总成本
            double expectedCost = CalculateExpectedTotalCost(adjustedLambda, optimalRetries);

            return new PoissonRetryStrategy
            {
                Lambda = adjustedLambda,
                OptimalRetryCount = optimalRetries,
                RetryIntervals = retryIntervals,
                SuccessProbability = successProbability,
                ExpectedCost = expectedCost,
                StrategyType = DetermineStrategyType(currentVolatility),
                Timestamp = DateTime.UtcNow
            };
        }

        /// <summary>
        /// 根据条件动态调整λ参数
        /// </summary>
        /// <param name="operationType">操作类型</param>
        /// <param name="volatility">市场波动率</param>
        /// <param name="systemLoad">系统负载</param>
        /// <returns>调整后的λ参数</returns>
        private double AdjustLambdaForConditions(string operationType, double volatility, double systemLoad)
        {
            double adjustedLambda = _lambda;
            
            // 根据历史成功率调整
            if (_operationStats.ContainsKey(operationType))
            {
                var stats = _operationStats[operationType];
                double historicalSuccessRate = stats.SuccessRate;
                
                // 成功率高时降低λ（减少重试），成功率低时提高λ（增加重试）
                double successAdjustment = (1.0 - historicalSuccessRate) * 2.0;
                adjustedLambda *= (1.0 + successAdjustment);
            }
            
            // 根据市场波动率调整
            double volatilityAdjustment = 1.0;
            if (volatility >= VOLATILITY_HIGH_THRESHOLD)
            {
                // 高波动：增加重试频率（提高λ）
                volatilityAdjustment = 1.5;
            }
            else if (volatility <= VOLATILITY_NORMAL_THRESHOLD)
            {
                // 低波动：减少重试频率（降低λ）
                volatilityAdjustment = 0.8;
            }
            
            adjustedLambda *= volatilityAdjustment;
            
            // 根据系统负载调整
            double loadAdjustment = 1.0 - (systemLoad * 0.3); // 负载高时减少重试
            adjustedLambda *= loadAdjustment;
            
            // 确保λ在合理范围内
            return Math.Max(MIN_LAMBDA, Math.Min(MAX_LAMBDA, adjustedLambda));
        }

        /// <summary>
        /// 计算最优重试次数
        /// 基于成本函数优化：TC(n,t) = n × C_attempt + E[T(n,t)] × C_time + P_failure(n) × C_failure
        /// </summary>
        /// <param name="lambda">泊松参数</param>
        /// <returns>最优重试次数</returns>
        private int CalculateOptimalRetryCount(double lambda)
        {
            int optimalN = 1;
            double minCost = double.MaxValue;
            
            // 遍历可能的重试次数，找到最小成本
            for (int n = 1; n <= 20; n++) // 最大考虑20次重试
            {
                double successProb = CalculateSuccessProbability(lambda, n);
                double failureProb = 1.0 - successProb;
                
                // 如果成功概率已达到目标，检查成本
                if (successProb >= TARGET_SUCCESS_RATE)
                {
                    double totalCost = CalculateExpectedTotalCost(lambda, n);
                    
                    if (totalCost < minCost)
                    {
                        minCost = totalCost;
                        optimalN = n;
                    }
                }
                
                // 如果成功概率足够高且成本开始增加，停止搜索
                if (successProb >= 0.999 && n > optimalN)
                {
                    break;
                }
            }
            
            return optimalN;
        }

        /// <summary>
        /// 计算重试间隔序列
        /// 基于泊松过程的等待时间分布：指数分布间隔
        /// </summary>
        /// <param name="lambda">泊松参数</param>
        /// <param name="retryCount">重试次数</param>
        /// <returns>重试间隔毫秒数组</returns>
        private int[] CalculateRetryIntervals(double lambda, int retryCount)
        {
            var intervals = new int[retryCount];
            
            for (int i = 0; i < retryCount; i++)
            {
                // 泊松过程的等待时间服从指数分布
                // 指数分布的期望值为 1/λ
                double u = _randomProvider.NextDouble();
                
                // 避免log(0)的情况
                if (u <= 0) u = 0.0001;
                
                double interval = -Math.Log(u) / lambda;
                
                // 转换为毫秒，并加入适当的基础延迟
                int intervalMs = (int)(interval * 1000) + 50; // 最小50ms间隔
                
                // 限制间隔范围：50ms - 5000ms
                intervalMs = Math.Max(50, Math.Min(5000, intervalMs));
                
                intervals[i] = intervalMs;
            }
            
            return intervals;
        }

        /// <summary>
        /// 计算n次重试的成功概率
        /// P_success(n) = 1 - e^(-nλt)，这里简化为 P_success(n) = 1 - e^(-nλ)
        /// </summary>
        /// <param name="lambda">泊松参数</param>
        /// <param name="retryCount">重试次数</param>
        /// <returns>成功概率</returns>
        private double CalculateSuccessProbability(double lambda, int retryCount)
        {
            // 简化模型：每次重试成功概率为 1 - e^(-λ)
            double singleAttemptFailProb = Math.Exp(-lambda);
            double overallFailProb = Math.Pow(singleAttemptFailProb, retryCount);
            
            return 1.0 - overallFailProb;
        }

        /// <summary>
        /// 计算期望总成本
        /// </summary>
        /// <param name="lambda">泊松参数</param>
        /// <param name="retryCount">重试次数</param>
        /// <returns>期望总成本</returns>
        private double CalculateExpectedTotalCost(double lambda, int retryCount)
        {
            double successProb = CalculateSuccessProbability(lambda, retryCount);
            double failureProb = 1.0 - successProb;
            
            // 重试成本
            double retryCost = retryCount * _attemptCost;
            
            // 时间成本：基于平均等待时间
            double avgWaitTime = retryCount / lambda; // 简化的期望等待时间
            double timeCost = avgWaitTime * _timeCost;
            
            // 失败成本
            double failureCost = failureProb * _failureCost;
            
            return retryCost + timeCost + failureCost;
        }

        /// <summary>
        /// 确定重试策略类型
        /// </summary>
        /// <param name="volatility">市场波动率</param>
        /// <returns>策略类型</returns>
        private RetryStrategyType DetermineStrategyType(double volatility)
        {
            if (volatility >= VOLATILITY_HIGH_THRESHOLD)
            {
                return RetryStrategyType.Aggressive; // 高波动：激进重试
            }
            else if (volatility >= VOLATILITY_NORMAL_THRESHOLD)
            {
                return RetryStrategyType.Balanced;   // 中等波动：平衡重试
            }
            else
            {
                return RetryStrategyType.Conservative; // 低波动：保守重试
            }
        }

        #endregion

        #region 统计学习方法

        /// <summary>
        /// 记录重试尝试结果，用于参数学习
        /// </summary>
        /// <param name="operationType">操作类型</param>
        /// <param name="attemptsCount">实际重试次数</param>
        /// <param name="success">是否成功</param>
        /// <param name="totalTime">总耗时（毫秒）</param>
        public void RecordAttemptResult(string operationType, int attemptsCount, bool success, long totalTime)
        {
            lock (_statisticsLock)
            {
                // 记录到历史队列
                var record = new RetryAttemptRecord
                {
                    OperationType = operationType,
                    AttemptsCount = attemptsCount,
                    Success = success,
                    TotalTime = totalTime,
                    Timestamp = DateTime.UtcNow
                };
                
                _attemptHistory.Enqueue(record);
                
                // 维护窗口大小
                while (_attemptHistory.Count > HISTORY_WINDOW_SIZE)
                {
                    _attemptHistory.Dequeue();
                }
                
                // 更新操作统计
                if (!_operationStats.ContainsKey(operationType))
                {
                    _operationStats[operationType] = new OperationStatistics();
                }
                
                var stats = _operationStats[operationType];
                stats.TotalAttempts++;
                if (success)
                {
                    stats.SuccessCount++;
                }
                stats.SuccessRate = (double)stats.SuccessCount / stats.TotalAttempts;
                stats.LastUpdated = DateTime.UtcNow;
            }
            
            // 自适应学习调整λ参数
            UpdateLambdaBasedOnResults();
        }

        /// <summary>
        /// 基于历史结果更新λ参数
        /// </summary>
        private void UpdateLambdaBasedOnResults()
        {
            if (_attemptHistory.Count < 10) return; // 数据不足，不调整
            
            // 计算最近的平均成功率
            var recentAttempts = _attemptHistory.TakeLast(20).ToArray();
            double recentSuccessRate = recentAttempts.Count(a => a.Success) / (double)recentAttempts.Length;
            
            // 如果成功率过低，增加λ；如果成功率很高，可以略微减少λ
            double adjustment = 0.0;
            if (recentSuccessRate < 0.90)
            {
                adjustment = LEARNING_RATE * (0.95 - recentSuccessRate);
            }
            else if (recentSuccessRate > 0.99)
            {
                adjustment = -LEARNING_RATE * 0.1; // 小幅降低
            }
            
            // 应用调整
            _lambda = Math.Max(MIN_LAMBDA, Math.Min(MAX_LAMBDA, _lambda * (1.0 + adjustment)));
        }

        /// <summary>
        /// 获取操作类型的统计信息
        /// </summary>
        /// <param name="operationType">操作类型</param>
        /// <returns>统计信息</returns>
        public OperationStatistics GetOperationStatistics(string operationType)
        {
            lock (_statisticsLock)
            {
                return _operationStats.ContainsKey(operationType) ? _operationStats[operationType] : null;
            }
        }

        /// <summary>
        /// 获取系统整体统计报告
        /// </summary>
        /// <returns>统计报告</returns>
        public PoissonRetryReport GenerateReport()
        {
            lock (_statisticsLock)
            {
                var recentAttempts = _attemptHistory.TakeLast(50).ToArray();
                
                return new PoissonRetryReport
                {
                    CurrentLambda = _lambda,
                    TotalAttempts = _attemptHistory.Count,
                    RecentSuccessRate = recentAttempts.Length > 0 ? 
                        recentAttempts.Count(a => a.Success) / (double)recentAttempts.Length : 0.0,
                    AverageRetryCount = recentAttempts.Length > 0 ? 
                        recentAttempts.Average(a => a.AttemptsCount) : 0.0,
                    AverageResponseTime = recentAttempts.Length > 0 ? 
                        recentAttempts.Average(a => a.TotalTime) : 0.0,
                    OperationCount = _operationStats.Count,
                    GeneratedAt = DateTime.UtcNow
                };
            }
        }

        #endregion

        #region 内部数据结构

        /// <summary>
        /// 重试尝试记录
        /// </summary>
        private class RetryAttemptRecord
        {
            public string OperationType { get; set; }
            public int AttemptsCount { get; set; }
            public bool Success { get; set; }
            public long TotalTime { get; set; }
            public DateTime Timestamp { get; set; }
        }

        #endregion
    }

    #region 公共数据结构

    /// <summary>
    /// 泊松重试策略
    /// </summary>
    public class PoissonRetryStrategy
    {
        /// <summary>
        /// 泊松参数λ
        /// </summary>
        public double Lambda { get; set; }

        /// <summary>
        /// 最优重试次数
        /// </summary>
        public int OptimalRetryCount { get; set; }

        /// <summary>
        /// 重试间隔序列（毫秒）
        /// </summary>
        public int[] RetryIntervals { get; set; }

        /// <summary>
        /// 预期成功概率
        /// </summary>
        public double SuccessProbability { get; set; }

        /// <summary>
        /// 预期总成本
        /// </summary>
        public double ExpectedCost { get; set; }

        /// <summary>
        /// 策略类型
        /// </summary>
        public RetryStrategyType StrategyType { get; set; }

        /// <summary>
        /// 生成时间
        /// </summary>
        public DateTime Timestamp { get; set; }

        private readonly PoissonRetryExecutor _executor;
        private readonly IRandomProvider _randomProvider;

        /// <summary>
        /// 构造函数（带随机数提供器）
        /// </summary>
        public PoissonRetryStrategy(IRandomProvider randomProvider)
        {
            _randomProvider = randomProvider;
            _executor = new PoissonRetryExecutor(1.0, randomProvider);
            Lambda = 1.0;
            OptimalRetryCount = 3;
            RetryIntervals = new int[] { 1000, 2000, 4000 };
            SuccessProbability = 0.8;
            ExpectedCost = 1.0;
            StrategyType = RetryStrategyType.Balanced;
            Timestamp = DateTime.UtcNow;
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public PoissonRetryStrategy() : this(null)
        {
        }

        /// <summary>
        /// 执行带重试的异步操作
        /// </summary>
        public async Task<T> ExecuteWithRetryAsync<T>(
            Func<Task<T>> operation,
            string operationName = "Operation",
            int? maxRetries = null,
            Func<Exception, bool> shouldRetry = null)
        {
            if (_executor != null)
            {
                return await _executor.ExecuteWithRetryAsync(
                    operation,
                    operationName,
                    maxRetries ?? OptimalRetryCount,
                    shouldRetry);
            }
            else
            {
                // 如果没有executor，直接执行操作
                return await operation();
            }
        }
    }

    /// <summary>
    /// 重试策略类型
    /// </summary>
    public enum RetryStrategyType
    {
        Conservative,  // 保守策略：低波动环境
        Balanced,      // 平衡策略：正常波动环境
        Aggressive     // 激进策略：高波动环境
    }

    /// <summary>
    /// 操作统计信息
    /// </summary>
    public class OperationStatistics
    {
        public int TotalAttempts { get; set; } = 0;
        public int SuccessCount { get; set; } = 0;
        public double SuccessRate { get; set; } = 0.0;
        public DateTime LastUpdated { get; set; } = DateTime.UtcNow;
    }

    /// <summary>
    /// 泊松重试系统报告
    /// </summary>
    public class PoissonRetryReport
    {
        /// <summary>
        /// 当前λ参数
        /// </summary>
        public double CurrentLambda { get; set; }
        
        /// <summary>
        /// 总尝试次数
        /// </summary>
        public int TotalAttempts { get; set; }
        
        /// <summary>
        /// 最近成功率
        /// </summary>
        public double RecentSuccessRate { get; set; }
        
        /// <summary>
        /// 平均重试次数
        /// </summary>
        public double AverageRetryCount { get; set; }
        
        /// <summary>
        /// 平均响应时间（毫秒）
        /// </summary>
        public double AverageResponseTime { get; set; }
        
        /// <summary>
        /// 操作类型数量
        /// </summary>
        public int OperationCount { get; set; }
        
        /// <summary>
        /// 报告生成时间
        /// </summary>
        public DateTime GeneratedAt { get; set; }
    }

    #endregion
}


